package com.cloudlinkscm.base.filecenter.domain;

import com.cloudlinkscm.base.filecenter.common.FileUtil;
import com.cloudlinkscm.base.filecenter.exception.FileEmptyException;
import com.cloudlinkscm.base.filecenter.exception.FileSaveException;
import com.cloudlinkscm.base.filecenter.model.FileRecord;
import com.cloudlinkscm.base.filecenter.model.FileStream;
import com.cloudlinkscm.base.filecenter.model.SysAuthCode;
import com.cloudlinkscm.base.filecenter.model.bo.DocumentSaveBo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.io.InputStream;
import java.util.Date;
import java.util.UUID;

/**
 * 定义文件仓库接口
 *
 * @author : tac
 * @date : 2017/7/24
 */
public abstract class AbstractFileStorage {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    protected SysAuthCodeManager sysAuthCodeManager;
    public AbstractFileRecordManager fileRecordManager;
    protected FileStreamManager fileStreamManager;

    public AbstractFileStorage(SysAuthCodeManager sysAuthCodeManager, AbstractFileRecordManager fileRecordManager, FileStreamManager fileStreamManager) {
        this.sysAuthCodeManager = sysAuthCodeManager;
        this.fileRecordManager = fileRecordManager;
        this.fileStreamManager = fileStreamManager;
    }

    public FileRecord saveDocument(DocumentSaveBo bo, MultipartFile document){
        if (FileUtil.isEmpty(document)) {
            throw new FileEmptyException();
        }

        int rowNum = 0;

        String location = generateStoredName();     //以存储名作为相对路径
        FileRecord newRecord = fileRecordManager.buildFileRecord(bo, document, location);

        if (StringUtils.isNotBlank(newRecord.getId())) {
            FileRecord oldRecord = fileRecordManager.dao.selectByPrimaryKey(newRecord.getId());
            if (null != oldRecord) {
                rowNum += fileRecordManager.dao.updateByPrimaryKeySelective(newRecord);       //先update是为了防止操作失败把文件先删除了
                store(document, bo.getSysCode(), location);
                remove(oldRecord.getSysCode(), oldRecord.getLocation());
            }
        } else {
            rowNum += fileRecordManager.dao.insert(newRecord);
            store(document, bo.getSysCode(), location);
        }

        return newRecord;
    }

    public String saveImage(){
        throw new NotImplementedException();
    }


    public FileStream createStream(FileRecord record) {
        return fileStreamManager.createStream(record, (this::buildStoredLocation));
    }

    /**
     * 删除指定文件
     * <br/>
     * 文件数据会被物理删除，文件记录只是逻辑删除
     */
    public int delete(FileRecord record){
        int rowNum = fileRecordManager.delete(record.getId());
        remove(record.getSysCode(), record.getLocation());
        return rowNum;
    }

    /**
     * 保存文件到仓库
     * @return 文件存储绝对路径，保存失败为null
     */
    protected abstract String store(MultipartFile file, String sysCode, String relativeLocation);

    /**
     * 从仓库中移除现有文件
     * @param sysCode 系统编码
     * @param relativePath 相对路径
     * @return
     */
    protected abstract void remove(String sysCode, String relativePath);

    /**
     * 构建文件存储的绝对路径
     * @param storedName 文件名
     * @param auth 授权信息
     */
    protected abstract String buildStoredLocation(String storedName, SysAuthCode auth);

    /**
     * 从仓库中获取文件流
     */
    public abstract InputStream getFileInputStream(FileStream stream);

    protected String generateStoredName(){
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

}
